﻿Imports System.Text
Imports Microsoft.VisualStudio.Utilities
Imports System.IO
Imports System.Xml.Serialization
Imports System.Xml

Namespace VsSpeakerCompanion
	''' <summary>
	''' Manages the Speaker settings.
	''' </summary>
	Public Class Settings
        Private Const DefaultSettingsPath = "Settings.xml"
        Private mSettingsPath As String

        Private values As Dictionary(Of String, Object)

        ''' <summary>
        ''' Creates a new instance of <see cref="Settings"/>
        ''' </summary>
        Public Sub New()
            Me.New(DefaultSettingsPath)
        End Sub

        ''' <summary>
        ''' Gets the path where the settings is being saved
        ''' </summary>
        Public ReadOnly Property SettingsPath As String
            Get
                Return Me.mSettingsPath
            End Get
        End Property

        ''' <summary>
        ''' Creates a new instance of <see cref="Settings"/>
        ''' </summary>
        ''' <param name="settingsPath"></param>
        Public Sub New(ByVal settingsPath As String)
            Me.values = New Dictionary(Of String, Object)()
            Me.mSettingsPath = settingsPath

            If Not Path.IsPathRooted(Me.mSettingsPath) Then
                Me.mSettingsPath = Path.Combine(Path.GetDirectoryName(Me.GetType().Assembly.Location), Me.mSettingsPath)
            End If
        End Sub

        ''' <summary>
        ''' Updates the setting value for the specified key
        ''' </summary>
        ''' <param name="key"></param>
        ''' <param name="value"></param>
        Public Overridable Sub Update(ByVal key As String, ByVal value As Object)
            If Me.values.ContainsKey(key) Then
                Me.values.Remove(key)
            End If

            Me.values.Add(key, value)
        End Sub

        ''' <summary>
        ''' Gets the property value for the specified key
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="key"></param>
        ''' <returns></returns>
        Public Overridable Function [Get](Of T)(ByVal key As String) As T
            If Not String.IsNullOrEmpty(key) Then
                Dim value = Nothing
                If Me.values.TryGetValue(key, value) Then
                    Return CType(value, T)
                End If
            End If

            Return Nothing
        End Function

        ''' <summary>
        ''' Loads the settings
        ''' </summary>
        Public Sub Load()
            If File.Exists(mSettingsPath) Then
                Dim serializer As New XmlSerializer(GetType(List(Of SettingValue)))

                Using reader = XmlReader.Create(mSettingsPath)
                    Dim entries = TryCast(serializer.Deserialize(reader), List(Of SettingValue))
                    values.Clear()
                    ' Convert the list of settings to the dictionary
                    entries.ForEach(Sub(entry) values.Add(entry.Key, entry.Value))
                End Using
            End If
        End Sub

        Private Sub EnsureSettingsFile()
            If File.Exists(mSettingsPath) Then
                If (File.GetAttributes(mSettingsPath) And FileAttributes.ReadOnly) <> 0 Then
                    File.SetAttributes(mSettingsPath, FileAttributes.Normal)
                End If
            Else
                Dim myPath = Path.GetDirectoryName(mSettingsPath)

                If Not Directory.Exists(myPath) Then
                    Directory.CreateDirectory(myPath)
                End If
            End If
        End Sub

        ''' <summary>
        ''' Saves the settings
        ''' </summary>
        Friend Sub Save()
            EnsureSettingsFile()

            Dim serializer As New XmlSerializer(GetType(List(Of SettingValue)))
            Dim settings As New XmlWriterSettings
            settings.Indent = True

            Using writer = XmlWriter.Create(mSettingsPath, settings)
                ' Convert the dictionary of settings to a List and use the serializer to save them
                Dim entries As New List(Of SettingValue)
                Me.values.ToList().ForEach(Sub(value) entries.Add(New SettingValue With {.Key = value.Key, .Value = value.Value}))

                serializer.Serialize(writer, entries)
            End Using
        End Sub
	End Class
End Namespace